from libs.PipeLine import PipeLine, ScopedTiming
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
import os
import ujson
from media.media import *
import nncase_runtime as nn
import ulab.numpy as np
import image
import gc
import sys
import aidemo
from machine import Pin
from machine import FPIOA
import time
import math

class PersonKeyPointApp(AIBase):
    # 保持原有代码不变
    def __init__(self, kmodel_path, model_input_size, confidence_threshold=0.1, nms_threshold=0.5, rgb888p_size=[1280, 720], display_size=[1920, 1080], debug_mode=0):
        super().__init__(kmodel_path, model_input_size, rgb888p_size, debug_mode)
        self.kmodel_path = kmodel_path
        self.model_input_size = model_input_size
        self.confidence_threshold = confidence_threshold
        self.nms_threshold = nms_threshold
        self.rgb888p_size = [ALIGN_UP(rgb888p_size[0], 16), rgb888p_size[1]]
        self.display_size = [ALIGN_UP(display_size[0], 16), display_size[1]]
        self.debug_mode = debug_mode
        self.SKELETON = [(16, 14), (14, 12), (17, 15), (15, 13), (12, 13), (6, 12), (7, 13), (6, 7), (6, 8), (7, 9), (8, 10), (9, 11), (2, 3), (1, 2), (1, 3), (2, 4), (3, 5), (4, 6), (5, 7)]
        self.LIMB_COLORS = [(255, 51, 153, 255), (255, 51, 153, 255), (255, 51, 153, 255), (255, 51, 153, 255), (255, 255, 51, 255), (255, 255, 51, 255), (255, 255, 51, 255), (255, 255, 128, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0)]
        self.KPS_COLORS = [(255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 0, 255, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 255, 128, 0), (255, 51, 153, 255), (255, 51, 153, 255), (255, 51, 153, 255), (255, 51, 153, 255), (255, 51, 153, 255), (255, 51, 153, 255)]
        self.ai2d = Ai2d(debug_mode)
        self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT, nn.ai2d_format.NCHW_FMT, np.uint8, np.uint8)

    def config_preprocess(self, input_image_size=None):
        with ScopedTiming("set preprocess config", self.debug_mode > 0):
            ai2d_input_size = input_image_size if input_image_size else self.rgb888p_size
            top, bottom, left, right = self.get_padding_param()
            self.ai2d.pad([0, 0, 0, 0, top, bottom, left, right], 0, [0, 0, 0])
            self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)
            self.ai2d.build([1, 3, ai2d_input_size[1], ai2d_input_size[0]], [1, 3, self.model_input_size[1], self.model_input_size[0]])

    def postprocess(self, results):
        with ScopedTiming("postprocess", self.debug_mode > 0):
            results = aidemo.person_kp_postprocess(results[0], [self.rgb888p_size[1], self.rgb888p_size[0]], self.model_input_size, self.confidence_threshold, self.nms_threshold)
            return results

    def draw_result(self, pl, res):
        with ScopedTiming("display_draw", self.debug_mode > 0):
            if res[0]:
                pl.osd_img.clear()
                kpses = res[1]
                for i in range(len(res[0])):
                    for k in range(17 + 2):
                        if k < 17:
                            kps_x, kps_y, kps_s = round(kpses[i][k][0]), round(kpses[i][k][1]), kpses[i][k][2]
                            kps_x1 = int(float(kps_x) * self.display_size[0] // self.rgb888p_size[0])
                            kps_y1 = int(float(kps_y) * self.display_size[1] // self.rgb888p_size[1])
                            if kps_s > 0:
                                pl.osd_img.draw_circle(kps_x1, kps_y1, 5, self.KPS_COLORS[k], 4)
                        ske = self.SKELETON[k]
                        pos1_x, pos1_y = round(kpses[i][ske[0]-1][0]), round(kpses[i][ske[0]-1][1])
                        pos1_x_ = int(float(pos1_x) * self.display_size[0] // self.rgb888p_size[0])
                        pos1_y_ = int(float(pos1_y) * self.display_size[1] // self.rgb888p_size[1])

                        pos2_x, pos2_y = round(kpses[i][(ske[1]-1)][0]), round(kpses[i][(ske[1]-1)][1])
                        pos2_x_ = int(float(pos2_x) * self.display_size[0] // self.rgb888p_size[0])
                        pos2_y_ = int(float(pos2_y) * self.display_size[1] // self.rgb888p_size[1])

                        pos1_s, pos2_s = kpses[i][(ske[0]-1)][2], kpses[i][(ske[1]-1)][2]
                        if pos1_s > 0.0 and pos2_s > 0.0:
                            pl.osd_img.draw_line(pos1_x_, pos1_y_, pos2_x_, pos2_y_, self.LIMB_COLORS[k], 4)
                    pl.osd_img.draw_circle(kps_x1, kps_y1, 3, (0, 255, 0), 2)  # 绿色圆心表示肩臀中点
                    gc.collect()
            else:
                pl.osd_img.clear()

    def get_padding_param(self):
        dst_w = self.model_input_size[0]
        dst_h = self.model_input_size[1]
        input_width = self.rgb888p_size[0]
        input_high = self.rgb888p_size[1]
        ratio_w = dst_w / input_width
        ratio_h = dst_h / input_high
        ratio = min(ratio_w, ratio_h)
        new_w = int(ratio * input_width)
        new_h = int(ratio * input_high)
        dw = (dst_w - new_w) // 2
        dh = (dst_h - new_h) // 2
        return dh, dh, dw, dw

class MultiBehaviorDetector:
    def __init__(self, display_size, rgb888p_size, debug_mode=3):  # 新增debug_mode参数
        self.display_size = display_size
        self.rgb888p_size = rgb888p_size
        # self.min_confidence = 0.5 # 关键点置信度最小阈值
        self.min_confidence = 0.4   
        self.prev_positions = {}  # 存储上一帧的位置
        
        # 新增参数
        self.fall_slope_threshold = 1.0  # 跌倒斜率阈值
        self.run_speed_threshold = 1.2   # 奔跑速度阈值
        self.crowd_distance_threshold = 1.2  # 聚集距离阈值
        self.crowd_centers_threshold = 0.3  # 聚集对数阈值
        
        # 新增：调试模式
        self.debug_mode = debug_mode
        self.frame_count = 0  # 帧计数器，用于调试

        # 打架检测参数
        self.arm_angle_threshold = 0.1  # 手臂角度变化阈值（弧度）
        self.body_angle_threshold = 0.1  # 身体倾斜角度阈值
        self.fight_frame_threshold = 1  # 连续检测到打架的帧数阈值
        self.min_people_involved = 2  # 判定打架所需的最少人数
        
        # 状态存储
        self.prev_arm_angles = {}  # 存储上一帧的手臂角度
        self.fight_frames = {}  # 存储连续检测到打架的帧数
        self.frame_count = 0  # 总帧数计数器

    def update_params(self, min_confidence=None, punch_threshold=None, 
                      fall_slope=None, run_speed=None, crowd_distance=None, crowd_centers=None
                      ,fight_speed=None, fight_accel=None):
        """更新MultiBehaviorDetector类的参数，增加参数校验"""
        if min_confidence is not None:
            if not (0 <= min_confidence <= 1):
                raise ValueError(f"min_confidence必须在[0,1]范围内，当前值: {min_confidence}")
            self.min_confidence = min_confidence
            
        if punch_threshold is not None:
            if punch_threshold < 1:
                raise ValueError(f"punch_threshold必须>=1，当前值: {punch_threshold}")
            self.punch_threshold = punch_threshold
            
        # 其他参数校验...
        if fall_slope is not None:
            self.fall_slope_threshold = fall_slope
        if run_speed is not None:
            self.run_speed_threshold = run_speed
        if crowd_distance is not None:
            self.crowd_distance_threshold = crowd_distance
        if crowd_centers is not None:
            self.crowd_centers_threshold = crowd_centers
        if fight_speed is not None:
            self.fight_speed_threshold = fight_speed
        if fight_accel is not None:
            self.fight_accel_threshold = fight_accel
    
    # 新增：通用关键点置信度检查
    def _check_keypoint_confidence(self, keypoints, indices):
        """检查指定索引的关键点置信度是否都达标"""
        for idx in indices:
            if keypoints[idx][2] < self.min_confidence:
                # if self.debug_mode > 1:
                    # print(f"关键点 {idx} 置信度不足: {keypoints[idx][2]} < {self.min_confidence}")
                return False
        return True
    
    def get_view_type(self, keypoints):
        """判断视图类型（正视图或侧视图）"""
        if not self._check_keypoint_confidence(keypoints, [5, 6]):  # 左右肩
            return None
            
        left_shoulder = keypoints[5]
        right_shoulder = keypoints[6]
        shoulder_distance = math.sqrt((right_shoulder[0] - left_shoulder[0])**2 + 
                                     (right_shoulder[1] - left_shoulder[1])**2)
        return "front" if shoulder_distance > 50 else "side"

    def get_reference_distance(self, keypoints):
        """根据视图类型获取参考距离"""
        view_type = self.get_view_type(keypoints)
        if view_type is None:
            return 0
            
        left_shoulder = keypoints[5]
        right_shoulder = keypoints[6]
        shoulder_distance = math.sqrt((right_shoulder[0] - left_shoulder[0])**2 + 
                                     (right_shoulder[1] - left_shoulder[1])**2)
                                     
        return shoulder_distance * 2 if view_type == "front" else shoulder_distance * 1.5

    def detect_run(self, keypoints, current_time):
        """改进版奔跑检测算法"""
        # 提取关键点并检查置信度
        if not self._check_keypoint_confidence(keypoints, [11, 12, 13, 14]):  # 左右髋、膝
            return False
            
        left_hip, right_hip = keypoints[11], keypoints[12]
        left_knee, right_knee = keypoints[13], keypoints[14]
        
        # 计算髋关节和膝关节的垂直距离
        left_hip_knee_dist = abs(left_knee[1] - left_hip[1])
        right_hip_knee_dist = abs(right_knee[1] - right_hip[1])
        
        # 计算身体移动速度
        person_id = hash((round((left_hip[0] + right_hip[0])/2), 
                         round((left_hip[1] + right_hip[1])/2)))
        
        # 使用髋关节中点作为参考点
        ref_point = ((left_hip[0] + right_hip[0])/2, (left_hip[1] + right_hip[1])/2)
        
        # 计算速度
        speed = self._calculate_speed(person_id, "body", ref_point, current_time)
        
        # 奔跑特征：
        # 1. 身体移动速度超过阈值
        # 2. 双腿关节垂直距离变化较大（跑步时膝盖会弯曲）
        is_running = speed > self.run_speed_threshold and \
                    (left_hip_knee_dist < 50 or right_hip_knee_dist < 50)
        
        if self.debug_mode > 0 and is_running:
            print(f"检测到奔跑: 速度={speed:.2f}, 左膝距={left_hip_knee_dist}, 右膝距={right_hip_knee_dist}")
            
        return is_running

    def _calculate_speed(self, person_id, part_name, position, current_time):
        """计算关键点移动速度"""
        key = "{0}_{1}".format(person_id, part_name)
        
        # 检查并修复可能的错误数据
        if key in self.prev_positions:
            prev_data = self.prev_positions[key]
            if not isinstance(prev_data, (list, tuple)) or len(prev_data) != 3:
                print("[WARN] {0}格式错误，重置数据".format(key))
                self.prev_positions[key] = (position[0], position[1], current_time)
                return 0
                
        # 计算速度
        if key in self.prev_positions:
            prev_x, prev_y, prev_time = self.prev_positions[key]
            dx = position[0] - prev_x
            dy = position[1] - prev_y
            dt = current_time - prev_time
            
            if self.debug_mode > 3:
                print("[DEBUG] 速度计算参数 - dx: {0}, dy: {1}, dt: {2}".format(dx, dy, dt))
                
            if dt > 0:
                speed = math.sqrt(dx**2 + dy** 2) / dt
                self.prev_positions[key] = (position[0], position[1], current_time)
                if self.debug_mode > 2:
                    print("[DEBUG] 人物{0} {1}速度: {2:.2f}".format(person_id, part_name, speed))
                return speed
                
        # 首次存储位置数据
        self.prev_positions[key] = (position[0], position[1], current_time)
        if self.debug_mode > 3:
            print("[DEBUG] 初始化人物{0} {1}位置: ({2}, {3})".format(person_id, part_name, position[0], position[1]))
        return 0



    def detect_crowd(self, all_keypoints, current_time):
        """改进版聚集检测算法"""
        centers = []
        
        # 新增：输出输入的关键点数量
        # print(f"[detect_crowd] 输入关键点数量: {len(all_keypoints)}")
        
        if len(all_keypoints) > 3:
            # 计算每个人的中心点和身体尺寸
            for kp in all_keypoints:
                # 检查关键点置信度
                if not self._check_keypoint_confidence(kp, [5, 6, 11, 12]):
                    # 新增：输出置信度不足的关键点索引
                    missing_keypoints = [idx for idx in [5, 6, 11, 12] if kp[idx][2] < self.min_confidence]
                    # print(f"[detect_crowd] 跳过：关键点 {missing_keypoints} 置信度不足")
                    continue
                    
                left_shoulder, right_shoulder = kp[5], kp[6]
                left_hip, right_hip = kp[11], kp[12]
                
                # 计算身体中心
                center_x = (left_shoulder[0] + right_shoulder[0] + left_hip[0] + right_hip[0]) / 4
                center_y = (left_shoulder[1] + right_shoulder[1] + left_hip[1] + right_hip[1]) / 4
                
                # 计算身体宽度和高度
                width = max(abs(right_shoulder[0] - left_shoulder[0]), 
                        abs(right_hip[0] - left_hip[0]))
                height = max(abs(right_shoulder[1] - right_hip[1]), 
                            abs(left_shoulder[1] - left_hip[1]))
                reference_size = (width + height) / 2
                
                # 新增：输出每个人的计算结果
                # print(f"[detect_crowd] 人物中心: ({center_x:.2f}, {center_y:.2f}), 宽: {width:.2f}, 高: {height:.2f}, 参考尺寸: {reference_size:.2f}")
                
                centers.append((center_x, center_y, reference_size))
            
            # 新增：输出最终有效人数
            # print(f"[detect_crowd] 有效人数: {len(centers)}")
            
            # 计算人群密度
            crowd_count = 0
            for i in range(len(centers)):
                for j in range(i + 1, len(centers)):
                    dx = centers[i][0] - centers[j][0]
                    dy = centers[i][1] - centers[j][1]
                    distance = math.sqrt(dx**2 + dy**2)
                    avg_size = (centers[i][2] + centers[j][2]) / 2
                    
                    # 新增：输出每对人的距离计算
                    # print(f"[detect_crowd] 人物{i}与{i+1}距离: {distance:.2f}, 平均尺寸: {avg_size:.2f}, 阈值比例: {self.crowd_distance_threshold}")
                    
                    if distance < avg_size * self.crowd_distance_threshold:
                        crowd_count += 1
                        # print(f"[detect_crowd] 判定为近距离对 (距离: {distance:.2f} < {avg_size*self.crowd_distance_threshold:.2f})")
            
            # 新增：输出聚集对数和阈值
            threshold = len(centers) * self.crowd_centers_threshold
            # print(f"[detect_crowd] 聚集对数: {crowd_count}, 阈值: {threshold}")
            
            # 判断是否聚集
            is_crowd = crowd_count > threshold
            
            # if self.debug_mode > 0 and is_crowd:
            #     print(f"检测到人群聚集: {len(centers)}人中有{crowd_count}对近距离")
            if len(centers)>3:
                return is_crowd
            else:
                False
        else:
            # 新增：输出跳过原因（人数不足）
            # print(f"[detect_crowd] 跳过：有效人数不足（当前{len(all_keypoints)}人 < 3人）")
            return False
   
    def detect_fall(self, keypoints, current_time):
        """改进版跌倒检测算法"""
        # 提取关键点并检查置信度
        if not self._check_keypoint_confidence(keypoints, [6, 12, 15]):  # 右肩、右髋、右脚
            return False
            
        right_shoulder, right_hip, right_foot = keypoints[6], keypoints[12], keypoints[15]
        
        # 计算身体倾斜角度
        dx_shoulder_hip = right_hip[0] - right_shoulder[0]
        dy_shoulder_hip = right_hip[1] - right_shoulder[1]
        
        dx_hip_foot = right_foot[0] - right_hip[0]
        dy_hip_foot = right_foot[1] - right_hip[1]
        
        # 避免除零错误
        shoulder_hip_slope = float('inf') if dx_shoulder_hip == 0 else dy_shoulder_hip / dx_shoulder_hip
        hip_foot_slope = float('inf') if dx_hip_foot == 0 else dy_hip_foot / dx_hip_foot
            
        # 检查身体是否接近水平
        is_horizontal = (abs(shoulder_hip_slope) < 0.5) or (abs(hip_foot_slope) < 0.5)
        
        # 检查双脚是否接近肩部高度
        foot_shoulder_distance = abs(right_foot[1] - right_shoulder[1])
        shoulder_width = abs(keypoints[5][0] - keypoints[6][0])
        
        is_low = foot_shoulder_distance < shoulder_width * 0.7
        
        is_fall = is_horizontal and is_low
        
        if self.debug_mode > 0 and is_fall:
            print(f"检测到跌倒: 肩髋斜率={shoulder_hip_slope:.2f}, 髋脚斜率={hip_foot_slope:.2f}, 脚肩距={foot_shoulder_distance}")
            
        return is_fall
    
        
    def detect_fight(self, all_keypoints):
        """简化版打架检测算法 - 仅基于角度变化"""
        if len(all_keypoints) < self.min_people_involved:
            if self.debug_mode > 0:
                print(f"[DEBUG] 人数不足({len(all_keypoints)})，跳过检测")
            return False
            
        self.frame_count += 1
        fight_detected = False
        people_involved = 0
        
        for i, kp in enumerate(all_keypoints):
            # 跳过置信度不足的人
            if not self._check_keypoint_confidence(kp, [5, 6, 11, 12]):  # 双肩和双髋
                continue
                
            person_id = i  # 简化ID，使用索引
            
            # 计算手臂角度变化
            left_arm_angle = self._calculate_arm_angle(kp, "left")
            right_arm_angle = self._calculate_arm_angle(kp, "right")
            
            # 计算身体倾斜角度
            body_angle = self._calculate_body_angle(kp)
            
            # 检查是否有打架特征
            is_fighting = self._check_fighting_features(person_id, left_arm_angle, right_arm_angle, body_angle)
            
            if is_fighting:
                people_involved += 1
                if self.debug_mode > 0:
                    print(f"[DEBUG] 人物{person_id}被判定为参与打架")
            
            # 记录检测结果
            if is_fighting:
                if person_id not in self.fight_frames:
                    self.fight_frames[person_id] = 1
                else:
                    self.fight_frames[person_id] += 1
            else:
                # 未检测到打架，重置计数器
                if person_id in self.fight_frames:
                    self.fight_frames[person_id] -= 1
                    if self.fight_frames[person_id] <= 0:
                        del self.fight_frames[person_id]
        
        # 检查是否有足够多的人持续参与打架
        if people_involved >= self.min_people_involved:
            # 统计连续检测到打架的人数
            continuous_fighters = 0
            for person_id, frames in self.fight_frames.items():
                if frames >= self.fight_frame_threshold:
                    continuous_fighters += 1
                    
            if continuous_fighters >= self.min_people_involved:
                fight_detected = True
                if self.debug_mode > 0:
                    print(f"[ALERT] 检测到打架行为！涉及{continuous_fighters}人，持续{self.fight_frame_threshold}帧以上")
        
        if self.debug_mode > 1 and not fight_detected:
            print(f"[DEBUG] 未检测到打架，涉及{people_involved}人，需要至少{self.min_people_involved}人")
            
        return fight_detected
    
    def _check_keypoint_confidence(self, keypoints, indices):
        """检查指定关键点的置信度是否足够"""
        for idx in indices:
            if len(keypoints[idx]) < 3 or keypoints[idx][2] < 0.3:  # 置信度阈值
                return False
        return True
    
    def _calculate_arm_angle(self, keypoints, side):
        """计算手臂角度 (肩-肘-腕)"""
        shoulder_idx = 5 if side == "left" else 6
        elbow_idx = 7 if side == "left" else 8
        wrist_idx = 9 if side == "left" else 10
        
        shoulder = keypoints[shoulder_idx]
        elbow = keypoints[elbow_idx]
        wrist = keypoints[wrist_idx]
        
        # 计算向量
        vector1 = (elbow[0] - shoulder[0], elbow[1] - shoulder[1])
        vector2 = (wrist[0] - elbow[0], wrist[1] - elbow[1])
        
        # 计算角度
        dot_product = vector1[0] * vector2[0] + vector1[1] * vector2[1]
        cross_product = vector1[0] * vector2[1] - vector1[1] * vector2[0]
        
        # 使用atan2计算有符号角度，范围[-π, π]
        angle = math.atan2(cross_product, dot_product)
        
        return angle
    
    def _calculate_body_angle(self, keypoints):
        """计算身体倾斜角度 (肩中点-髋中点)"""
        left_shoulder = keypoints[5]
        right_shoulder = keypoints[6]
        left_hip = keypoints[11]
        right_hip = keypoints[12]
        
        # 计算肩中点和髋中点
        shoulder_center = ((left_shoulder[0] + right_shoulder[0]) / 2, 
                          (left_shoulder[1] + right_shoulder[1]) / 2)
                          
        hip_center = ((left_hip[0] + right_hip[0]) / 2, 
                     (left_hip[1] + right_hip[1]) / 2)
        
        # 计算身体向量
        body_vector = (hip_center[0] - shoulder_center[0], 
                      hip_center[1] - shoulder_center[1])
                      
        # 计算与垂直方向的角度
        vertical_vector = (0, 1)
        
        dot_product = body_vector[0] * vertical_vector[0] + body_vector[1] * vertical_vector[1]
        cross_product = body_vector[0] * vertical_vector[1] - body_vector[1] * vertical_vector[0]
        
        # 使用atan2计算有符号角度，范围[-π, π]
        angle = math.atan2(cross_product, dot_product)
        
        return angle
    
    def _check_fighting_features(self, person_id, left_arm_angle, right_arm_angle, body_angle):
        """检查是否有打架特征"""
        # 初始化上一帧数据
        if person_id not in self.prev_arm_angles:
            self.prev_arm_angles[person_id] = {
                "left": left_arm_angle,
                "right": right_arm_angle,
                "body": body_angle,
                "frame": self.frame_count
            }
            return False
            
        prev_data = self.prev_arm_angles[person_id]
        
        # 计算角度变化
        left_angle_change = abs(left_arm_angle - prev_data["left"])
        right_angle_change = abs(right_arm_angle - prev_data["right"])
        body_angle_change = abs(body_angle - prev_data["body"])
        
        # 处理角度跨π的情况
        if left_angle_change > math.pi:
            left_angle_change = 2 * math.pi - left_angle_change
        if right_angle_change > math.pi:
            right_angle_change = 2 * math.pi - right_angle_change
        if body_angle_change > math.pi:
            body_angle_change = 2 * math.pi - body_angle_change
            
        # 更新上一帧数据
        self.prev_arm_angles[person_id] = {
            "left": left_arm_angle,
            "right": right_arm_angle,
            "body": body_angle,
            "frame": self.frame_count
        }
        
        # 调试输出
        if self.debug_mode > 2:
            print(f"[DEBUG] 人物{person_id}角度变化 - 左手臂: {left_angle_change:.2f}, 右手臂: {right_angle_change:.2f}, 身体: {body_angle_change:.2f}")
        
        # 判断是否有打架特征
        # 1. 至少一只手臂有剧烈角度变化
        # 2. 身体有明显倾斜
        arm_movement = left_angle_change > self.arm_angle_threshold or \
                      right_angle_change > self.arm_angle_threshold
                      
        body_movement = body_angle_change > self.body_angle_threshold
        
        return arm_movement and body_movement    
    
    
    def clean_history(self, max_age=1.0):
        """增强版历史数据清理，支持二元组（速度/角度）和三元组（位置）格式"""
        current_time = time.time()
        keys_to_delete = []
        
        for key in list(self.prev_positions.keys()):
            try:
                value = self.prev_positions[key]
                # 检查值是否为序列
                if not isinstance(value, (list, tuple)):
                    print(f"清理历史数据时出错 - Key: {key}, 错误: 值不是序列类型，类型为 {type(value)}")
                    keys_to_delete.append(key)
                    continue
                    
                # 区分角度相关键（结尾含_angle）、速度相关键（结尾含_speed）和位置相关键
                is_angle_key = "_angle" in key
                is_speed_key = "_speed" in key
                
                # 获取时间戳
                if is_angle_key or is_speed_key:
                    # 角度/速度数据应为 (value, timestamp) 二元组
                    if len(value) != 2:
                        print(f"警告: {key}数据长度异常: {len(value)}，预期2")
                        keys_to_delete.append(key)
                        continue
                    timestamp = value[1]  # 时间戳在索引1
                else:
                    # 位置数据应为 (x, y, timestamp) 三元组
                    if len(value) != 3:
                        print(f"警告: {key}数据长度异常: {len(value)}，预期3")
                        keys_to_delete.append(key)
                        continue
                    timestamp = value[2]  # 时间戳在索引2
                
                # 校验时间戳类型
                if not isinstance(timestamp, (int, float)):
                    print(f"警告: {key}时间戳类型错误: {type(timestamp)}")
                    keys_to_delete.append(key)
                    continue
                    
                # 判断是否过期
                if current_time - timestamp > max_age:
                    keys_to_delete.append(key)
                    
            except Exception as e:
                print(f"清理历史数据时发生意外错误 - Key: {key}, 错误: {str(e)}")
                keys_to_delete.append(key)
        
        # 安全删除过期键
        for key in keys_to_delete:
            try:
                # print(f"清理前: 历史数据大小={len(self.prev_positions)}")
                del self.prev_positions[key]
                # print(f"清理后: 历史数据大小={len(self.prev_positions)}")
            except KeyError:
                pass


def init_ai_model(kmodel_path, rgb888p_size, display_size):
    person_kp = PersonKeyPointApp(
        kmodel_path,
        model_input_size=[320, 320],
        confidence_threshold=0.1,
        nms_threshold=0.5,
        rgb888p_size=rgb888p_size,
        display_size=display_size
    )
    person_kp.config_preprocess()
    
    detector = MultiBehaviorDetector(display_size, rgb888p_size)
    return person_kp, detector

# 执行AI推理
def run_inference(person_kp, detector, pl, current_time):
    img = pl.get_frame()
    res = person_kp.run(img)

    detection_results = {
        "fall": False,
        "run": False,
        "crowd": False,
        "fight": False  # 新增打架检测结果
    }

    if res[0] and len(res[1]) > 0:
        all_keypoints = res[1]

        # 单人检测
        for keypoints in all_keypoints:
            if detector.detect_fall(keypoints, current_time):
                detection_results["fall"] = True
                print("⚠️ 检测到跌倒")
            if detector.detect_run(keypoints, current_time):
                detection_results["run"] = True
                print("⚠️ 检测到奔跑")

        # 多人检测
        if len(all_keypoints) >= 2:
            if detector.detect_crowd(all_keypoints, current_time):
                detection_results["crowd"] = True
                print("⚠️ 检测到聚集")
            if detector.detect_fight(all_keypoints):  
                detection_results["fight"] = True
                print("⚠️ 检测到打架")
    print(f"剩余内存: {gc.mem_free()}")
    person_kp.draw_result(pl, res)
    detector.frame_count = (detector.frame_count + 1) % 10
    if detector.frame_count == 0:
        detector.clean_history()
    return detection_results